/*
 *  Copyright (C) 2025 Andrés Martínez Mera - andresmmera@protonmail.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "SParameterCalculator.h"

void SParameterCalculator::exportTouchstone(const QString& filename,
                                            const vector<vector<Complex>>& S) {
  QFile file(filename);
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    cerr << "Error: Cannot create output file " << filename.toStdString()
         << endl;
    return;
  }

  QTextStream out(&file);

  // Write header
  out << "! Touchstone file generated by SParameterCalculator\n";
  out << "# GHz S MA R " << ports[0].impedance << "\n";

  // Write S-parameters
  double freqGHz = frequency / 1e9;
  out << freqGHz;

  for (size_t i = 0; i < S.size(); i++) {
    for (size_t j = 0; j < S[i].size(); j++) {
      double mag   = abs(S[i][j]);
      double phase = arg(S[i][j]) * 180.0 / M_PI;
      out << " " << mag << " " << phase;
    }
  }

  out << "\n";

  file.close();
  cout << "S-parameters exported to " << filename.toStdString() << endl;
}

void SParameterCalculator::exportSweepTouchstone(
    const QString& filename) const {
  QFile file(filename);
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    cerr << "Error: Cannot create output file " << filename.toStdString()
         << endl;
    return;
  }

  QTextStream out(&file);

  // Write header
  out << "! Touchstone file generated by SParameterCalculator\n";
  out << "# GHz S MA R " << (ports.empty() ? 50.0 : ports[0].impedance) << "\n";

  // Write S-parameters for each frequency
  double step = (n_points == 1) ? 0 : (f_stop - f_start) / (n_points - 1);

  for (int i = 0; i < n_points; ++i) {
    double freq    = f_start + i * step;
    double freqGHz = freq / 1e9;
    const auto& S  = sweepResults[i];

    out << freqGHz;

    for (const auto& rowVec : S) {
      for (const auto& value : rowVec) {
        double mag   = abs(value);
        double phase = arg(value) * 180.0 / M_PI;
        out << " " << mag << " " << phase;
      }
    }

    out << "\n";
  }

  file.close();
  cout << "Frequency sweep exported to " << filename.toStdString() << endl;
}

void SParameterCalculator::printSParameters(const vector<vector<Complex>>& S) {
  int numPorts = S.size();

  cout << "S-Parameters at frequency " << frequency / 1e9 << " GHz:" << endl;
  cout << "----------------------------------------" << endl;

  for (int i = 0; i < numPorts; i++) {
    for (int j = 0; j < numPorts; j++) {
      double mag   = abs(S[i][j]);
      double phase = arg(S[i][j]) * 180.0 / M_PI;
      double magDB = 20 * log10(mag);

      cout << "S(" << i + 1 << "," << j + 1 << "): " << mag << " ∠" << phase
           << "° " << "(" << magDB << " dB)" << endl;
    }
  }
}

void SParameterCalculator::printSParameterSweep() const {
  double step = (n_points == 1) ? 0 : (f_stop - f_start) / (n_points - 1);

  for (int i = 0; i < n_points; ++i) {
    double freq   = f_start + i * step;
    const auto& S = sweepResults[i];
    int numPorts  = S.size();

    std::cout << "S-Parameters at frequency " << freq / 1e9 << " GHz (" << freq
              << " Hz):\n";
    std::cout << "----------------------------------------\n";

    for (int i = 0; i < numPorts; ++i) {
      for (int j = 0; j < numPorts; ++j) {
        double mag   = abs(S[i][j]);
        double phase = arg(S[i][j]) * 180.0 / M_PI;
        double magDB = 20 * log10(mag);
        std::cout << "S(" << i + 1 << "," << j + 1 << "): " << mag << " ∠"
                  << phase << "° " << "(" << magDB << " dB)\n";
      }
    }
    std::cout << std::endl;
  }
}
